
#ifndef _TTG_UTILS_PARAMETERS_SPECIFIC_PARAMETERS_
#define _TTG_UTILS_PARAMETERS_SPECIFIC_PARAMETERS_
#include "Common/Definitions.h"

#include "Parameter.h"

namespace ttg_internal
{
	namespace utils
	{
		//Specific version, that allows using of range.
		template <class T>
		class RangedParameter :public ttg::utils::Parameter<T>
		{
			private:
				T lo, hi;
				bool has_bounds;
			private:
				//Returns serialized ranged type.
				static std::string getRangedType(T lo, T hi)
				{ return TypeSerializer::serializeVoid(); }
			public:
				//Creates parameter, that is equal to Parameter<T>.
				RangedParameter(const char *name = "Unnamed")
					:Parameter<T>(name)
				{ has_bounds = false; lo = hi = (T)0.0; }
				//Creates parameter, that is equal to Parameter<T>.
				RangedParameter(const char *name, ttg::utils::ParameterSet *owner)
					:Parameter<T>(name, owner)
				{ has_bounds = false; lo = hi = (T)0.0; }
				//Creates parameter, that is equal to Parameter<T>.
				RangedParameter(const char *name, const T &value)
					:Parameter<T>(name, value)
				{ has_bounds = false; lo = hi = (T)0.0; }
				//Creates parameter, that is equal to Parameter<T>.
				RangedParameter(const char *name, ttg::utils::ParameterSet *owner, const T &value)
					:Parameter<T>(name, owner, value)
				{ has_bounds = false; lo = hi = (T)0.0; }
				//Creates parameter with ranged type.
				RangedParameter(const char *name, T lo, T hi)
					:Parameter<T>(true, name, getRangedType(lo, hi).c_str())
				{
					has_bounds = true;
					this->lo = lo;
					this->hi = hi;
				}
				//Creates parameter with ranged type.
				RangedParameter(const char *name, ttg::utils::ParameterSet *owner, T lo, T hi)
					:Parameter<T>(true, name, getRangedType(lo, hi).c_str(), owner)
				{
					has_bounds = true;
					this->lo = lo;
					this->hi = hi;
				}
				//Assigns value.
				inline const T &operator =(const T &value)
				{ return (*(Parameter<T> *)this) = value; }
				//Returns true, if this parameter has bounds.
				inline bool hasBounds()
				{ return has_bounds; }
				//Returns low bound.
				inline T getLowBound()
				{ return lo; }
				//Returns hight bound.
				inline T getHighBound()
				{ return hi; }
		};
		template <>
		static std::string RangedParameter<ttg::math::int32>::getRangedType(ttg::math::int32 lo,
																			ttg::math::int32 hi)
		{ return TypeSerializer::serializeInt64(lo, hi); }
		template <>
		static std::string RangedParameter<double>::getRangedType(double lo, double hi)
		{ return TypeSerializer::serializeDouble(lo, hi); }
	}
}

namespace ttg
{
	namespace utils
	{
		//Ranged int parameter.
		typedef ttg_internal::utils::RangedParameter<ttg::math::int32> ParameterInt;
		//Ranged double parameter.
		typedef ttg_internal::utils::RangedParameter<double> ParameterDouble;

		//Implements enumeration parameter.
		class ParameterEnum :public Parameter<std::string>
		{
			private:
				std::vector<std::string> elements;
				//Parses elements of enum.
				static std::vector<std::string> parseElements(const char *elements);
			public:
				//Creates enumeration with required elements.
				//Format: "e1|el2|el3"
				ParameterEnum(const char *name, const char *elements);
				//Creates enumeration with required elements.
				//Format: "e1|el2|el3"
				ParameterEnum(const char *name, ParameterSet *owner, const char *elements);
				//Returns count of elements.
				inline size_t getCount()
				{ return elements.size(); }
				//Returns index of required element.
				size_t operator[] (const char *el);
				//Returns element with required index.
				inline const std::string &operator[] (size_t index)
				{ return elements[index]; }
				//Assigns index-th element.
				size_t operator =(size_t index);
				//Assigns requred element.
				inline const std::string &operator =(const std::string &value)
				{ return (*(Parameter<std::string> *)this) = value; }
				//Casts parameter to element's index.
				inline operator size_t()
				{ return (*this)[((std::string)*this).c_str()]; }
		};
	}
}

#endif
